package view

import (
	"encoding/binary"
	"fmt"
	_ "golang.org/x/text/encoding"
)

type ClassReader struct {
	data []byte
	pos  uint64
}

func (self *ClassReader) readUInt8() uint8 {
	b1 := self.data[self.pos]
	self.pos += 1
	return b1
}

func (self *ClassReader) readUInt16(data []uint8) uint16 {
	b2 := binary.BigEndian.Uint16(data)
	return b2
}

func (self *ClassReader) readUInt32(data []uint8) uint32 {
	b4 := binary.BigEndian.Uint32(data)
	return b4
}

func (self *ClassReader) readUInt64(data []uint8) uint64 {
	b8 := binary.BigEndian.Uint64(data)
	return b8
}

func (self *ClassReader) readUInt8s(n uint16) []uint8 {
	arr := make([]uint8, n)
	for i := 0; i < int(n); i++ {
		arr[i] = self.readUInt8()
	}
	return arr
}

func (self *ClassReader) readUInt8s2(n uint32) []uint8 {
	arr := make([]uint8, n)
	for i := 0; i < int(n); i++ {
		arr[i] = self.readUInt8()
	}
	return arr
}

func (self *ClassReader) readUtf8(len uint16) string {
	u8s := self.readUInt8s(len)
	/**
	  这里要说明一下
	  字符串在class文件中是以MUTF-8的方式编码的 这里是近似解码 go默认是UTF8解码  对大多数情况这样解码是没有问题的
	  但是 null字符串 或者 补充字符串 会有影响
	*/
	data, _ := decodeMUTF8(u8s)
	return string(data)
}

// 判断字节是否为MUTF-8的标记字节
func isMarkerByte(b byte) bool {
	return b >= 0xC0 && b <= 0xF7
}

// 解码MUTF-8编码
func decodeMUTF8(data []uint8) ([]rune, error) {
	var decoded []rune
	i := 0
	for i < len(data) {
		if !isMarkerByte(data[i]) {
			decoded = append(decoded, rune(data[i]))
			i++
		} else if data[i] == 0xC0 { // 两字节字符的开始标记
			if i+1 >= len(data) || !isMarkerByte(data[i+1]) {
				return nil, fmt.Errorf("invalid MUTF-8 encoding")
			}
			decoded = append(decoded, rune((data[i]&0x1F)<<6|data[i+1]&0x3F))
			i += 2
		} else if data[i] == 0xE0 { // 三字节字符的开始标记
			if i+2 >= len(data) || data[i+1] < 0x80 || !isMarkerByte(data[i+2]) {
				return nil, fmt.Errorf("invalid MUTF-8 encoding")
			}
			decoded = append(decoded, rune((data[i]&0x0F)<<12|(data[i+1]&0x3F)<<6|data[i+2]&0x3F))
			i += 3
		} else { // 四字节字符的开始标记（目前Go只支持到三字节）
			return nil, fmt.Errorf("invalid MUTF-8 encoding")
		}
	}
	return decoded, nil
}
